package Day020_NIO_AIO.demo1_Selector选择器.Test3_Selector多路复用;

import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;

/**
 * @author zhangyan
 * @date 2020/5/13 11:02
 */
public class Server {
    public static void main(String[] args) throws Exception {

        //创建3个通道，同时监听3个端口
        //获取ServerSocketChannel对象
        ServerSocketChannel channel1 = ServerSocketChannel.open();
        //设置非阻塞
        channel1.configureBlocking(false);
        //绑定端口号
        channel1.bind(new InetSocketAddress(7777));

        ServerSocketChannel channel2 = ServerSocketChannel.open();
        channel2.configureBlocking(false);
        channel2.bind(new InetSocketAddress(8888));

        ServerSocketChannel channel3 = ServerSocketChannel.open();
        channel3.configureBlocking(false);
        channel3.bind(new InetSocketAddress(9999));

        //获取选择器
        Selector selector = Selector.open();

        //把服务器通道的accept()交给选择器处理
        //注册通道Channel到Selector
        channel1.register(selector, SelectionKey.OP_ACCEPT);
        channel2.register(selector, SelectionKey.OP_ACCEPT);
        channel3.register(selector, SelectionKey.OP_ACCEPT);

        //服务器等客户端连接 循环监听三个通道
        while (true) {
            System.out.println("等待客户端连接...");
            selector.select(); // 阻塞
            System.out.println("连接数量:" + selector.select());

            //获取所有被连接的服务器Channel对象的set集合
            Set<SelectionKey> keySet = selector.selectedKeys();
            //循环遍历set集合(必须迭代器)
            Iterator<SelectionKey> it = keySet.iterator();
            //快捷键 itit
            while (it.hasNext()) {
                //遍历出来的SelectionKey
                SelectionKey key = it.next();

                //由于SelectionKey是对Channel的封装 我们可以根据key获取连接服务器的Channel对象
                ServerSocketChannel ssc = (ServerSocketChannel) key.channel();

                //处理客户端请求
                //获取连接的客户端对象
                SocketChannel sc = ssc.accept();
                //创建ByteBuffer缓冲数组
                ByteBuffer b = ByteBuffer.allocate(1024);
                //读取数据
                sc.read(b);
                b.flip();
                //打印
                System.out.println(new String(b.array(),0,sc.read(b)));

                //移除SelectionKey
                it.remove();
            }
        }
    }
}
/**
 * 问题就出现在获取selectedKeys()的集合。
 * 第一次的7777连接，selectedKeys()获取的集合中只有一个SelectionKey对象。
 * 第二次的8888连接，selectedKeys()获取的集合中有2个SelectionKey对象，一个是连接7777客户端的，另一
 * 个是连接8888客户端的。而此时应该只处理连接8888客户端的，所以在上一次处理完7777的数据后，应该将其SelectionKey对象移除
 * 需要用迭代器!
 */